#include <iostream>
#include <string>
#define BASIC 1000000000 //10^9
#define ACCURANCY 2 //(10^9)^ACCURANCY
#define BIGNUMBERREX "[-+][1-9][0-9]*\\.?[0-9]*|[-+]?[0-9]+\\.?[0-9]*|\\.[0-9]*";
#pragma once
using namespace std;
extern unsigned short precision;

bool setDivisionPrecision(unsigned short);



enum BNError { OUT_OF_RANGE_ERR, MEM_ALLOCK_ERR, INVALID_OPPERATION_ERR, ZERO_DEVISION_ERR };

class BNException  : public std::runtime_error
{ 

	public: BNException(unsigned int x) : std::runtime_error("")
			{
				switch (x)
				{
				case OUT_OF_RANGE_ERR: {cout << "OUT_OF_RANGE_ERR" <<endl;break;}
				case MEM_ALLOCK_ERR: {	cout << "MEM_ALLOCK_ERR" <<endl;break;}
				case INVALID_OPPERATION_ERR: {	cout << "INVALID_OPPERATION_ERR" <<endl;break;}
				case ZERO_DEVISION_ERR: {	cout << "ZERO_DEVISION_ERR" <<endl;break;}
				}
				
			}
};

class big_integer; //forward declaration

class big_number
{
protected:
	unsigned long* _num_array;
	bool _sign;
	unsigned short _arr_size;
	unsigned short _fractionalPart;
	string valstr;
	bool bnflag;

	bool validate( string);
	void calcArraySize( int, int);
	void createIntegerPart( string);
	void createFracturePart( string);
	void setSign( string);
	void strToArray( string);
	void init( string);
	
	
	big_number ABS(const big_number &)const;
	big_number ADD(const big_number &, const big_number &) const;
	big_number SUB(const big_number &,const big_number &) const;
	big_number MULTI(const big_number &,const big_number &)const;
	big_number DIVISION (const big_number &,const big_number &)const;

public:
	/*
	Ido	Constructors
	*/
	big_number();
	big_number(int, int);
    big_number(string);
	big_number(char);
	big_number(short);
	big_number(int);
	big_number(long);
	big_number(long long);
	big_number(unsigned char);
	big_number(unsigned short);
	big_number(unsigned int);
	big_number(unsigned long);
	big_number(unsigned long long);
	big_number(float);
	big_number(double);
	big_number(long double);
	big_number(const big_number&);
    ~big_number(); 
	
	/*
	Ido Compareing
	*/
	bool operator==(const big_number&) const;
	bool operator!=(const big_number&) const;
	bool operator< (const big_number&) const;
	bool operator> (const big_number&) const;
	bool operator<= (const big_number&) const;
	bool operator>= (const big_number&) const;
	
	/*
	Boris
	*/
	big_number operator + (const big_number&) const;
	big_number operator - (const big_number&) const;	
	big_number operator * (const big_number&) const;
	big_number operator / (const big_number&) const;
	//
	big_number operator = (const big_number & rhs);
	big_number operator +=(const big_number &rhs);
	big_number operator -=(const big_number &rhs);
	big_number operator *=(const big_number &rhs);
	big_number operator /=(const big_number &rhs);

	// operator - for big_number and big_integer
	big_number operator - ( big_integer &rhs);

	//Unary negation operator//
    big_number operator -();

	//Unary  operator +//
    big_number operator +();

	// Declare prefix and postfix increment operators.
	big_number& operator++();       // Prefix increment operator.
	big_number operator++(int);     // Postfix increment operator.

	// Declare prefix and postfix decrement operators.
	big_number& operator--();       // Prefix decrement operator.
	big_number operator--(int);     // Postfix decrement operator.

	//sqrt
	
		big_number SQRT();
	/*
	Kiril
	Input IO operator
	*/
	friend istream &operator>>( istream  &, big_number &);

	/*
	Kiril -	public Casting functions
	*/
	string toString() const;
	big_integer toBigInteger();
	char toChar();
	short toShort();
	int toInt();
	long toLong();
	long long toLongLong();
	unsigned char toUnsignedChar();
	unsigned short toUnsignedShort();
	unsigned int toUnsignedInt();
	unsigned long toUnsignedLong();
	unsigned long long toUnsignedLongLong();
	float toFloat();
	double toDouble();
	long double toLongDouble();

	/*
	Kiril -Implicit Casting
	*/
	operator big_integer();
	operator std::string();
	operator char();
	operator short();
	operator int(); 
	operator long();
	operator long long();
	operator unsigned char();
	operator unsigned short();
	operator unsigned int();
	operator unsigned long();
	operator unsigned long long();
	operator float();
	operator double();
	operator long double();	
};
/*
Author Kiril
bignumber to ostream declaration
*/
ostream& operator<<(ostream&,const big_number&);

/*
	Ido Compareing
*/
bool operator== (char&, big_number&);
bool operator!= (char&, big_number&);
bool operator< (char&, big_number&);
bool operator> (char&, big_number&);
bool operator<= (char&, big_number&);
bool operator>= (char&, big_number&);

bool operator== (short&, big_number&);
bool operator!= (short&, big_number&);
bool operator< (short&, big_number&);
bool operator> (short&, big_number&);
bool operator<= (short&, big_number&);
bool operator>= (short&, big_number&);

bool operator== (int&, big_number&);
bool operator!= (int&, big_number&);
bool operator< (int&, big_number&);
bool operator> (int&, big_number&);
bool operator<= (int&, big_number&);
bool operator>= (int&, big_number&);

bool operator== (long&, big_number&);
bool operator!= (long&, big_number&);
bool operator< (long&, big_number&);
bool operator> (long&, big_number&);
bool operator<= (long&, big_number&);
bool operator>= (long&, big_number&);

bool operator== (long long&, big_number&);
bool operator!= (long long&, big_number&);
bool operator< (long long&, big_number&);
bool operator> (long long&, big_number&);
bool operator<= (long long&, big_number&);
bool operator>= (long long&, big_number&);

bool operator== (unsigned char&, big_number&);
bool operator!= (unsigned char&, big_number&);
bool operator< (unsigned char&, big_number&);
bool operator> (unsigned char&, big_number&);
bool operator<= (unsigned char&, big_number&);
bool operator>= (unsigned char&, big_number&);

bool operator== (unsigned short&, big_number&);
bool operator!= (unsigned short&, big_number&);
bool operator< (unsigned short&, big_number&);
bool operator> (unsigned short&, big_number&);
bool operator<= (unsigned short&, big_number&);
bool operator>= (unsigned short&, big_number&);

bool operator== (unsigned int&, big_number&);
bool operator!= (unsigned int&, big_number&);
bool operator< (unsigned int&, big_number&);
bool operator> (unsigned int&, big_number&);
bool operator<= (unsigned int&, big_number&);
bool operator>= (unsigned int&, big_number&);

bool operator== (unsigned long&, big_number&);
bool operator!= (unsigned long&, big_number&);
bool operator< (unsigned long&, big_number&);
bool operator> (unsigned long&, big_number&);
bool operator<= (unsigned long&, big_number&);
bool operator>= (unsigned long&, big_number&);

bool operator== (unsigned long long&, big_number&);
bool operator!= (unsigned long long&, big_number&);
bool operator< (unsigned long long&, big_number&);
bool operator> (unsigned long long&, big_number&);
bool operator<= (unsigned long long&, big_number&);
bool operator>= (unsigned long long&, big_number&);

bool operator== (float&, big_number&);
bool operator!= (float&, big_number&);
bool operator< (float&, big_number&);
bool operator> (float&, big_number&);
bool operator<= (float&, big_number&);
bool operator>= (float&, big_number&);

bool operator== (double&, big_number&);
bool operator!= (double&, big_number&);
bool operator< (double&, big_number&);
bool operator> (double&, big_number&);
bool operator<= (double&, big_number&);
bool operator>= (double&, big_number&);

bool operator== (long double&, big_number&);
bool operator!= (long double&, big_number&);
bool operator< (long double&, big_number&);
bool operator> (long double&, big_number&);
bool operator<= (long double&, big_number&);
bool operator>= (long double&, big_number&);

//////////////////////////////////////////////////////////////////////////////
	 
	inline big_number operator - (const big_number &bn,  int param ){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  long param ){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  long long param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  unsigned int param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  unsigned long param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  unsigned long long param ){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  unsigned short param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  float param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  long double param){return bn-big_number(param);}
	inline big_number operator - (const big_number &bn,  double param ){return bn-big_number(param);}

	inline big_number operator - (int param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (long param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (long long param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (unsigned int param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (unsigned long param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (unsigned long long param,const big_number &bn ){return big_number(param)-bn;}
	inline big_number operator - (unsigned short param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (float param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (long double param,const big_number &bn){return big_number(param)-bn;}
	inline big_number operator - (double param,const big_number &bn ){return big_number(param)-bn;}

	inline big_number operator + (const big_number &bn,  int param ){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  long param ){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  long long param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  unsigned int param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  unsigned long param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  unsigned long long param ){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  unsigned short param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  float param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  long double param){return bn+big_number(param);}
	inline big_number operator + (const big_number &bn,  double param ){return bn+big_number(param);}

	inline big_number operator + (int param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (long param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (long long param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (unsigned int param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (unsigned long param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (unsigned long long param,const big_number &bn ){return big_number(param)+bn;}
	inline big_number operator + (unsigned short param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (float param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (long double param,const big_number &bn){return big_number(param)+bn;}
	inline big_number operator + (double param,const big_number &bn ){return big_number(param)+bn;}

	inline big_number operator * (const big_number &bn,  int param ){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  long param ){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  long long param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  unsigned int param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  unsigned long param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  unsigned long long param ){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  unsigned short param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  float param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  long double param){return bn*big_number(param);}
	inline big_number operator * (const big_number &bn,  double param ){return bn*big_number(param);}

	inline big_number operator * (int param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (long param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (long long param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (unsigned int param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (unsigned long param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (unsigned long long param,const big_number &bn ){return big_number(param)*bn;}
	inline big_number operator * (unsigned short param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (float param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (long double param,const big_number &bn){return big_number(param)*bn;}
	inline big_number operator * (double param,const big_number &bn ){return big_number(param)*bn;}

    inline big_number operator / (const big_number &bn,  int param ){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  long param ){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  long long param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  unsigned int param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  unsigned long param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  unsigned long long param ){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  unsigned short param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  float param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  long double param){return bn/big_number(param);}
	inline big_number operator / (const big_number &bn,  double param ){return bn/big_number(param);}

	inline big_number operator / (int param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (long param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (long long param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (unsigned int param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (unsigned long param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (unsigned long long param,const big_number &bn ){return big_number(param)/bn;}
	inline big_number operator / (unsigned short param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (float param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (long double param,const big_number &bn){return big_number(param)/bn;}
	inline big_number operator / (double param,const big_number &bn ){return big_number(param)/bn;}
	
	template <class T>
	string typeToString( T num);
	